﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace UI.TileEngine
{
    public class Tile
    {

        public enum NeighboorDirection
        {
            Top = 1,
            Right = 2,
            Bottom = 4,
            Left = 8,
            TopRight = 16,
            BottomRight = 32,
            BottomLeft = 64,
            TopLeft = 128
        }

        private TileLayer _layer;
        private Tileset _tileset;
        private Point _position;

        public Tile(TileLayer layer, Tileset tileset, Point position)
        {
            this._layer = layer;
            this._tileset = tileset;
            this._position = position;
        }

        public Tileset tileset
        {
            get
            {
                return this._tileset;
            }
            set
            {
                this._tileset = value;
            }
        }

        public TileLayer layer
        {
            get
            {
                return this._layer;
            }
            set
            {
                this._layer = value;
            }
        }

        public Point position
        {
            get
            {
                return this._position;
            }
            set
            {
                this._position = value;
            }
        }

        public void draw(SpriteBatch batch)
        {
            //Detect which doors are truly open or not
            NeighboorDirection ActiveDoors = 0;

            //Draw my non-diagonal tiles neighboor doors first
            if (!this.hasSameNeighboor(NeighboorDirection.Top))
            {
                ActiveDoors |= NeighboorDirection.Top;
            }
            if (!this.hasSameNeighboor(NeighboorDirection.Right))
            {
                ActiveDoors |= NeighboorDirection.Right;
            }
            if (!this.hasSameNeighboor(NeighboorDirection.Bottom))
            {
                ActiveDoors |= NeighboorDirection.Bottom;
            }
            if (!this.hasSameNeighboor(NeighboorDirection.Left))
            {
                ActiveDoors |= NeighboorDirection.Left;
            }

            //Draw the inner continuous corners only if diagonal neighboor is invalid and that my non-diagonal neighboors are similar
            if (((ActiveDoors & NeighboorDirection.Top) != NeighboorDirection.Top) && ((ActiveDoors & NeighboorDirection.Right) != NeighboorDirection.Right) && !this.hasSameNeighboor(NeighboorDirection.TopRight))
            {
                ActiveDoors |= NeighboorDirection.TopRight;
            }
            if (((ActiveDoors & NeighboorDirection.Bottom) != NeighboorDirection.Bottom) && ((ActiveDoors & NeighboorDirection.Right) != NeighboorDirection.Right) && !this.hasSameNeighboor(NeighboorDirection.BottomRight))
            {
                ActiveDoors |= NeighboorDirection.BottomRight;
            }
            if (((ActiveDoors & NeighboorDirection.Bottom) != NeighboorDirection.Bottom) && ((ActiveDoors & NeighboorDirection.Left) != NeighboorDirection.Left) && !this.hasSameNeighboor(NeighboorDirection.BottomLeft))
            {
                ActiveDoors |= NeighboorDirection.BottomLeft;
            }
            if (((ActiveDoors & NeighboorDirection.Top) != NeighboorDirection.Top) && ((ActiveDoors & NeighboorDirection.Left) != NeighboorDirection.Left) && !this.hasSameNeighboor(NeighboorDirection.TopLeft))
            {
                ActiveDoors |= NeighboorDirection.TopLeft;
            }

            //Detect the right tile to draw
            Tileset.NeighboorOrientationIndex IndexToDraw = Tileset.NeighboorOrientationIndex.None;
            switch(ActiveDoors)
            {
                case 0:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.None;
                    break;
                case NeighboorDirection.TopRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTR;
                    break;
                case NeighboorDirection.BottomRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneBR;
                    break;
                case NeighboorDirection.BottomLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneBL;
                    break;
                case NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTL;
                    break;
                case NeighboorDirection.TopRight | NeighboorDirection.BottomRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTRBR;
                    break;
                case NeighboorDirection.TopRight | NeighboorDirection.BottomLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTRBL;
                    break;
                case NeighboorDirection.TopRight | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTRTL;
                    break;
                case NeighboorDirection.BottomRight | NeighboorDirection.BottomLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneBRBL;
                    break;
                case NeighboorDirection.BottomRight | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneBRTL;
                    break;
                case NeighboorDirection.BottomLeft | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneBLTL;
                    break;
                case NeighboorDirection.TopRight | NeighboorDirection.BottomRight | NeighboorDirection.BottomLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTRBRBL;
                    break;
                case NeighboorDirection.TopRight | NeighboorDirection.BottomRight | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTRBRTL;
                    break;
                case NeighboorDirection.TopRight | NeighboorDirection.BottomLeft | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTRBLTL;
                    break;
                case NeighboorDirection.BottomRight | NeighboorDirection.BottomLeft | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneBRBLTL;
                    break;
                case NeighboorDirection.TopRight | NeighboorDirection.BottomRight | NeighboorDirection.BottomLeft | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.NoneTRBRBLTL;
                    break;
                case NeighboorDirection.Top:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.Top;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.BottomRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopBR;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.BottomLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopBL;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.BottomRight | NeighboorDirection.BottomLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopBRBL;
                    break;
                case NeighboorDirection.Right:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.Right;
                    break;
                case NeighboorDirection.Right | NeighboorDirection.BottomLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.RightBL;
                    break;
                case NeighboorDirection.Right | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.RightTL;
                    break;
                case NeighboorDirection.Right | NeighboorDirection.BottomLeft | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.RightBLTL;
                    break;
                case NeighboorDirection.Bottom:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.Bottom;
                    break;
                case NeighboorDirection.Bottom | NeighboorDirection.TopRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.BottomTR;
                    break;
                case NeighboorDirection.Bottom | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.BottomTL;
                    break;
                case NeighboorDirection.Bottom | NeighboorDirection.TopRight | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.BottomTRTL;
                    break;
                case NeighboorDirection.Left:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.Left;
                    break;
                case NeighboorDirection.Left | NeighboorDirection.TopRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.LeftTR;
                    break;
                case NeighboorDirection.Left | NeighboorDirection.BottomRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.LeftBR;
                    break;
                case NeighboorDirection.Left | NeighboorDirection.TopRight | NeighboorDirection.BottomRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.LeftTRBR;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Right:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopRight;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Right | NeighboorDirection.BottomLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopRightBL;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Bottom:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopBottom;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Left:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopLeft;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Left | NeighboorDirection.BottomRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopLeftBR;
                    break;
                case NeighboorDirection.Right | NeighboorDirection.Bottom:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.RightBottom;
                    break;
                case NeighboorDirection.Right | NeighboorDirection.Bottom | NeighboorDirection.TopLeft:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.RightBottomTL;
                    break;
                case NeighboorDirection.Right | NeighboorDirection.Left:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.RightLeft;
                    break;
                case NeighboorDirection.Bottom | NeighboorDirection.Left:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.BottomLeft;
                    break;
                case NeighboorDirection.Bottom | NeighboorDirection.Left | NeighboorDirection.TopRight:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.BottomLeftTR;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Right | NeighboorDirection.Bottom:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopRightBottom;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Right | NeighboorDirection.Left:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopRightLeft;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Bottom | NeighboorDirection.Left:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.TopBottomLeft;
                    break;
                case NeighboorDirection.Right | NeighboorDirection.Bottom | NeighboorDirection.Left:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.RightBottomLeft;
                    break;
                case NeighboorDirection.Top | NeighboorDirection.Right | NeighboorDirection.Bottom | NeighboorDirection.Left:
                    IndexToDraw = Tileset.NeighboorOrientationIndex.All;
                    break;
            }

            //Draw the tile
            batch.Draw(
                this._tileset.Texture, 
                new Rectangle(this._position.X * this._tileset.TileSize.X, this._position.Y * this._tileset.TileSize.Y, this._tileset.TileSize.X, this._tileset.TileSize.Y),
                this._tileset.TileToRect(this._tileset.IndexToTile((short)IndexToDraw)), 
                Color.White
            );
            
        }

        public bool hasSameNeighboor(NeighboorDirection direction)
        {
            Point target;
            if (direction == NeighboorDirection.Top && this._layer.hasTile(target = new Point(this._position.X, this._position.Y - 1)))
            {
                return this._layer.getTile(target).tileset == this._tileset;
            }
            else if (direction == NeighboorDirection.Right && this._layer.hasTile(target = new Point(this._position.X + 1, this._position.Y)))
            {
                return this._layer.getTile(target).tileset == this._tileset;
            }
            else if (direction == NeighboorDirection.Bottom && this._layer.hasTile(target = new Point(this._position.X, this._position.Y + 1)))
            {
                return this._layer.getTile(target).tileset == this._tileset;
            }
            else if (direction == NeighboorDirection.Left && this._layer.hasTile(target = new Point(this._position.X - 1, this._position.Y)))
            {
                return this._layer.getTile(target).tileset == this._tileset;
            }
            else if (direction == NeighboorDirection.TopRight && this._layer.hasTile(target = new Point(this._position.X + 1 , this._position.Y - 1)))
            {
                return this._layer.getTile(target).tileset == this._tileset;
            }
            else if (direction == NeighboorDirection.BottomRight && this._layer.hasTile(target = new Point(this._position.X + 1, this._position.Y + 1)))
            {
                return this._layer.getTile(target).tileset == this._tileset;
            }
            else if (direction == NeighboorDirection.BottomLeft && this._layer.hasTile(target = new Point(this._position.X - 1, this._position.Y + 1)))
            {
                return this._layer.getTile(target).tileset == this._tileset;
            }
            else if (direction == NeighboorDirection.TopLeft && this._layer.hasTile(target = new Point(this._position.X - 1, this._position.Y - 1)))
            {
                return this._layer.getTile(target).tileset == this._tileset;
            }
            return false;
        }

    }
}
